"use strict";

/* 闭包 */
{
    function lazy_sum(arr) {
        let sum = function () {
            return arr.reduce(function (x, y) {
                return x + y;
            });
        };

        return sum;
    }

    arr = [1, 2, 3, 5, 7];
    let f = lazy_sum(arr);
    f();
    // < 18

    
    let f1 = lazy_sum(arr);
    let f2 = lazy_sum(arr);
    f1 === f2;  // false
    f1();       // 18
    f2();       // 18
}

{
    function count() {
        let arr = [];
        for (var i = 1; i <= 3; i++) {
            arr.push(function () {
                return i * i;
            });
        }

        return arr;
    }

    let results = count();
    let f1 = results[0];
    let f2 = results[1];
    let f3 = results[2];

    f1();   // 16
    f2();   // 16
    f3();   // 16
}

{
    function count() {
        var arr = [];
        for (var i = 1; i <= 3; i++) {
            arr.push((function (n) {
                return function () {
                    return n * n;
                }
            })(i));
        }
        
        return arr;
    }

    var results = count();
    var f1 = results[0];
    var f2 = results[1];
    var f3 = results[2];

    f1(); // 1
    f2(); // 4
    f3(); // 9

    (function (x) {
        return x * x;
    })(3);
}

{
    function create_counter(initial) {
        let x = initial || 0;
        return {
            inc: function () {
                x += 1;
                return x;
            }
        };
    }

    let c1 = create_counter();
    c1.inc();   // 1
    c1.inc();   // 2
    c1.inc();   // 3

    let c2 = create_counter(10);
    c2.inc();   // 11
    c2.inc();   // 12
    c2.inc();   // 13
}

{
    function make_pow(n) {
        return function (x) {
            return Math.pow(x, n);
        };
    }

    let pow2 = make_pow(2);
    let pow3 = make_pow(3);

    console.log(pow2(5));   // 25
    console.log(pow3(3));   // 27
}

{
    // 定义数字 0
    let zero = function (f) {
        return function (x) {
            return x;
        };
    };

    // 定义数字 1
    let one = function (f) {
        return function (x) {
            return f(x);
        };
    }

    // 定义加法
    function add(m, n) {
        return function (f) {
            return function (x) {
                return m(f)(n(f)(x));
            };
        };
    }

    // 2 = 1 + 1
    let two = add(one, one);

    // let two = function (f) {
    //     return function (x) {
    //         return f(f(x));
    //     };
    // };

    // 3 = 1 + 2
    let three = add(one, two);

    // 5 = 2 + 3
    let five = add(two, three);

    (three(function () {
        console.log("print 3 times");
    }))();

    (five(function () {
        console.log("print 5 times");
    }))();
}